/******************************************************************************
 * FileName:    gwin_protocol_task.c
 * Desc:        协议
 *
 *
 * Author:      Lin
 * Notes:
 *
 ******************************************************************************/

/*-------------------------- Includes ---------------------------------------*/
#include "gwin_protocol_task.h"
#include "gwin_main_task.h"
#include "gwin_fifo.h"


/*-------------------------- Macro Definitions ------------------------------*/
#define LOCAL_DEBUG_EN                      ( 0 )
#if LOCAL_DEBUG_EN
#define GWIN_DEBUG(...)                     USER_DEBUG(__VA_ARGS__)
#else
#define GWIN_DEBUG(...)
#endif


#define GWIN_PROT_FIFO_MAX_LEN              ( 128 )
#define GWIN_PROT_LIST_MAX_LEN              ( 64 )


/*-------------------------- Type Declarations ------------------------------*/
/*----------- MCU串口协议 -----------*/
/**
 * @brief 协议 偏移
 *
 *      串口协议：   包头id（2Byte） + 指令类型（1Byte） + 数据长度（2Byte） + 数据内容（N Byte） + 和校验（1Byte） + 包尾（1Byte）
 *
 */
typedef enum _gwin_protocol_index
{
    GWIN_PROT_INDEX_HEAD_1,
    GWIN_PROT_INDEX_HEAD_2,
    GWIN_PROT_INDEX_CMD,
    GWIN_PROT_INDEX_PAYLOAD_LEN_1,
    GWIN_PROT_INDEX_PAYLOAD_LEN_2,
    GWIN_PROT_INDEX_PAYLOAD_DATA,
    GWIN_PROT_INDEX_MAX,
}gwin_protocol_index_t;
#define GWIN_PROT_HEAD_SEND                 ( 0xAA55 )          // 包头 模组 -> MCU
#define GWIN_PROT_HEAD_RECV                 ( 0x55AA )          // 包头 MCU -> 模组
#define GWIN_PROT_MIN_LEN                   ( GWIN_PROT_INDEX_MAX - 1 )             // 最小总长度

/**
 * @brief 协议回复
 */
typedef enum _gwin_protocol_ack
{
    GWIN_PROT_ACK_FAIL,
    GWIN_PROT_ACK_SUCCESS,
}gwin_protocol_ack_t;


/**
 * @brief 协议命令
 */
typedef struct _gwin_protocol_cmd_map
{
    uint8_t cmd;
    void (*func) (uint8_t cmd, uint8_t *data, uint16_t len);
}gwin_protocol_cmd_map_t;


/**
 * @brief 协议缓存
 */
typedef struct
{
    gwin_fifo_t fifo;
    uint8_t buf[GWIN_PROT_FIFO_MAX_LEN];
}gwin_protocol_fifo_t;

/**
 * @brief 协议队列
 */
typedef struct
{
    gwin_fifo_t fifo;
    uint8_t buf[GWIN_PROT_LIST_MAX_LEN];
}gwin_protocol_list_t;


/*-------------------------- Global Variables -------------------------------*/

/*-------------------------- Local Variables --------------------------------*/
static void gwin_protocol_ack(uint8_t cmd, uint8_t result);
static void gwin_protocol_network(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_reset_all_force(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_action(uint8_t cmd, uint8_t *data, uint16_t len);


/**
 * @brief 协议命令
 */
static const gwin_protocol_cmd_map_t gwin_protocol_cmd_map[] =
{
    { GWIN_PROT_CMD_NETWORK,                            gwin_protocol_network,                  },

    { GWIN_PROT_CMD_RESET_ALL_FORCE,                    gwin_protocol_reset_all_force,          },

    { GWIN_PROT_CMD_TEMP_ACTION,                        gwin_protocol_action,                   },
};
static const uint8_t gwin_protocol_cmd_map_cnt = sizeof(gwin_protocol_cmd_map) / sizeof(gwin_protocol_cmd_map[0]);

#if GWIN_PROT_RX_IRQ
static void *gwin_protocol_task_timer_uart_rx = NULL;
#endif
static void *gwin_protocol_task_timer_uart_tx = NULL;

static uint8_t protocol_task_init = 0;
#if GWIN_PROT_RX_IRQ
static gwin_protocol_fifo_t protocol_fifo_rx_mcu = { 0x00 };
static gwin_protocol_list_t protocol_list_rx_mcu = { 0x00 };
#endif
static gwin_protocol_fifo_t protocol_fifo_tx_mcu = { 0x00 };
static gwin_protocol_list_t protocol_list_tx_mcu = { 0x00 };


/*-------------------------- Functions Declarations -------------------------*/
static void gwin_protocol_task(void *arg);
#if GWIN_PROT_RX_IRQ
static void gwin_protocol_uart_rx_callback(void *arg);
#endif
static void gwin_protocol_uart_tx_callback(void *arg);

static void gwin_protocol_task_timer_msg_handle(gwin_protocol_task_msg_t *msg);
static void gwin_protocol_task_recv_msg_handle(gwin_protocol_task_msg_t *msg);
static void gwin_protocol_task_send_msg_handle(gwin_protocol_task_msg_t *msg);

static void gwin_protocol_send_to_mcu(uint8_t *data, uint16_t len);
static int8_t gwin_protocol_recv_from_mcu(uint8_t *data, uint16_t len);
static uint16_t gwin_protocol_pack_to_mcu(uint8_t *data, uint8_t cmd, uint16_t payload_len);
static void gwin_protocol_parse_from_mcu(uint8_t *data, uint16_t len);


/*-------------------------- Functions Definitions --------------------------*/
/*----------- 协议解析 -----------*/
/**
 * @brief 回复，成功/失败
 */
static void gwin_protocol_ack(uint8_t cmd, uint8_t result)
{
    uint8_t buf[GWIN_UART_MAX_LEN] = { 0x00 };
    uint8_t *payload_data = &buf[GWIN_PROT_INDEX_PAYLOAD_DATA];
    uint16_t payload_len = 0;
    uint16_t total_len = 0;

    payload_data[payload_len] = result;
    payload_len += 1;

    total_len = gwin_protocol_pack_to_mcu(buf, cmd, payload_len);
    gwin_protocol_send_to_mcu(buf, total_len);
}


/**
 * @brief 发送某个命令
 */
void gwin_protocol_send_cmd_to_mcu(uint8_t cmd)
{
    uint8_t buf[GWIN_UART_MAX_LEN] = { 0x00 };
    uint8_t *payload_data = &buf[GWIN_PROT_INDEX_PAYLOAD_DATA];
    uint16_t payload_len = 0;
    uint16_t total_len = 0;
    uint8_t find = 0;

    switch (cmd)
    {
        default:
            break;
    }

    if (find)
    {
        total_len = gwin_protocol_pack_to_mcu(buf, cmd, payload_len);

        gwin_protocol_send_to_mcu(buf, total_len);
    }
}


/**
 * @brief 网络
 */
static void gwin_protocol_network(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    uint8_t result = GWIN_PROT_ACK_SUCCESS;

    gwin_main_extern_action(MAIN_TASK_MSG_EX_ACT_SUBTYPE_NET_RESET);

    gwin_protocol_ack(cmd, result);
}

/**
 * @brief 强制复位所有参数（研发预留接口，防止错误，直接响应）
 */
static void gwin_protocol_reset_all_force(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    #define RESET_ALL_FORCE_CMD         "reset_all_force"
    // 转换后的命令：55 AA E0 00 0E 72 65 73 65 74 5F 61 6C 6C 5F 66 6F 72 63 65

    uint8_t cmd_str_len = strlen(RESET_ALL_FORCE_CMD);
    cmd_str_len = MAX(cmd_str_len, len);
    if (memcmp(data, RESET_ALL_FORCE_CMD, cmd_str_len) == 0)
    {
        gwin_main_extern_action(MAIN_TASK_MSG_EX_ACT_SUBTYPE_RESET_ALL_FORCE);
    }
}


/**
 * @brief 动作
 */
static void gwin_protocol_action(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    uint8_t result = GWIN_PROT_ACK_SUCCESS;

    switch (data[0])
    {
        default:
            result = GWIN_PROT_ACK_FAIL;
            break;
    }

    gwin_protocol_ack(cmd, result);
}





/*----------- 数据交互 MCU -----------*/
/**
 * @brief 发送数据
 */
static void gwin_protocol_send_to_mcu(uint8_t *data, uint16_t len)
{
    len = gwin_fifo_write(&protocol_fifo_tx_mcu.fifo, data, len);
    gwin_fifo_write(&protocol_list_tx_mcu.fifo, (uint8_t *)&len, sizeof(len));

    if (!os_timer_is_active(gwin_protocol_task_timer_uart_tx))
    {
        gwin_protocol_uart_tx_callback(NULL);
        os_timer_start(gwin_protocol_task_timer_uart_tx, 0);
    }
}

/**
 * @brief 接收数据
 *
 * @return 0:成功；
 *          长度错误：-1：少于最小；    -2：少于应接接收的长度；
 *          协议格式：-3：协议头错误；
 *          协议内容：-4：协议未定义；
 */
static int8_t gwin_protocol_recv_from_mcu(uint8_t *data, uint16_t len)
{
    uint16_t head;
    uint8_t cmd;
    uint16_t payload_len;
    uint16_t total_len;
    uint8_t find;

    if (len < GWIN_PROT_MIN_LEN)
    {
        return -1;
    }

    memcpy(&payload_len, &data[GWIN_PROT_INDEX_PAYLOAD_LEN_1], sizeof(payload_len));
    payload_len = HL_SWAP_U16(payload_len);
    total_len = payload_len + GWIN_PROT_MIN_LEN;
    if (len < total_len)
    {
        return -2;
    }

    memcpy(&head, &data[GWIN_PROT_INDEX_HEAD_1], sizeof(head));
    head = HL_SWAP_U16(head);
    if (head != GWIN_PROT_HEAD_RECV)
    {
        return -3;
    }

    find = 0;
    cmd = data[GWIN_PROT_INDEX_CMD];
    for (uint8_t i = 0; i < gwin_protocol_cmd_map_cnt; i++)
    {
        if (cmd == gwin_protocol_cmd_map[i].cmd && gwin_protocol_cmd_map[i].func != NULL)
        {
            find = 1;
            GWIN_DEBUG("cmd = %x", cmd);
            gwin_protocol_data_recv(PROTOCOL_TASK_DATA_WAY_MCU, data, len);
            break;
        }
    }

    if (!find)
    {
        return -4;
    }
    else
    {
        return 0;
    }
}


/**
 * @brief 打包数据
 */
static uint16_t gwin_protocol_pack_to_mcu(uint8_t *data, uint8_t cmd, uint16_t payload_len)
{
    uint16_t head = HL_SWAP_U16(GWIN_PROT_HEAD_SEND);
    uint16_t tmp_len = HL_SWAP_U16(payload_len);
    memcpy(&data[GWIN_PROT_INDEX_HEAD_1], &head, sizeof(head));
    data[GWIN_PROT_INDEX_CMD] = cmd;
    memcpy(&data[GWIN_PROT_INDEX_PAYLOAD_LEN_1], &tmp_len, sizeof(tmp_len));

    return (payload_len + GWIN_PROT_MIN_LEN);
}

/**
 * @brief 解析数据
 */
static void gwin_protocol_parse_from_mcu(uint8_t *data, uint16_t len)
{
    uint8_t cmd = data[GWIN_PROT_INDEX_CMD];
    uint8_t *payload_data = &data[GWIN_PROT_INDEX_PAYLOAD_DATA];
    uint16_t payload_len = 0;
    memcpy(&payload_len, &data[GWIN_PROT_INDEX_PAYLOAD_LEN_1], sizeof(payload_len));
    payload_len = HL_SWAP_U16(payload_len);

    for (uint8_t i = 0; i < gwin_protocol_cmd_map_cnt; i++)
    {
        if (cmd == gwin_protocol_cmd_map[i].cmd && gwin_protocol_cmd_map[i].func != NULL)
        {
            GWIN_DEBUG("cmd = %x", cmd);
            gwin_protocol_cmd_map[i].func(cmd, payload_data, payload_len);
            break;
        }
    }
}



/*----------- 任务 -----------*/
/**
 * @brief 接收数据
 */
void gwin_protocol_data_recv(uint8_t way, uint8_t *data, uint16_t len)
{
    gwin_protocol_task_msg_t msg = { 0 };
    msg.type = PROTOCOL_TASK_MSG_TYPE_RECV;
    msg.subtype = way;
    msg.data = data;
    msg.len = len;
    #if GWIN_PROT_RX_IRQ
    if (msg.subtype == PROTOCOL_TASK_DATA_WAY_MCU)
    {
        // 串口接收是从中断过来的，要特殊处理，消息放到main去做
        msg.len = gwin_fifo_write(&protocol_fifo_rx_mcu.fifo, data, msg.len);
        gwin_fifo_write(&protocol_list_rx_mcu.fifo, (uint8_t *)&msg, sizeof(gwin_protocol_task_msg_t));
    }
    else
    {
        gwin_send_msg_to_protocol_task(&msg);
    }
    #else
    gwin_send_msg_to_protocol_task(&msg);
    #endif
}

/**
 * @brief 发送数据
 */
void gwin_protocol_data_send_mcu(uint32_t type)
{
    gwin_protocol_task_msg_t msg = { 0 };
    msg.type = PROTOCOL_TASK_MSG_TYPE_SEND;
    msg.subtype = PROTOCOL_TASK_DATA_WAY_MCU;
    msg.param = type;
    gwin_send_msg_to_protocol_task(&msg);
}


/**
 * @brief 定时器消息处理
 */
static void gwin_protocol_task_timer_msg_handle(gwin_protocol_task_msg_t *msg)
{
    uint16_t subtype = msg->subtype;

    switch(subtype)
    {
        #if GWIN_PROT_RX_IRQ
        case PROTOCOL_TASK_MSG_TIMER_SUBTYPE_UART_RX:
            {
                if (gwin_fifo_length(&protocol_list_rx_mcu.fifo))
                {
                    uint8_t data[GWIN_UART_MAX_LEN] = { 0x00 };
                    gwin_protocol_task_msg_t _msg = { 0x00 };
                    gwin_fifo_read(&protocol_list_rx_mcu.fifo, (uint8_t *)&_msg, sizeof(gwin_protocol_task_msg_t));
                    gwin_fifo_read(&protocol_fifo_rx_mcu.fifo, (uint8_t *)&data, _msg.len);
                    _msg.data = data;
                    gwin_send_msg_to_protocol_task(&_msg);
                }
            }
            break;
        #endif

        case PROTOCOL_TASK_MSG_TIMER_SUBTYPE_UART_TX:
            {
                if (gwin_fifo_length(&protocol_list_tx_mcu.fifo))
                {
                    uint8_t data[GWIN_UART_MAX_LEN] = { 0x00 };
                    uint16_t len = 0;
                    // 读
                    gwin_fifo_read(&protocol_list_tx_mcu.fifo, (uint8_t *)&len, sizeof(len));
                    gwin_fifo_read(&protocol_fifo_tx_mcu.fifo, data, len);
                    // 发送
                    gwin_uart_send((const uint8_t *)data, len);
                    // 循环发送
                    os_timer_start(gwin_protocol_task_timer_uart_tx, 0);
                }
            }
            break;

        default:
            GWIN_DEBUG("Error : subtype of timer msg is unknown %d !!!", subtype);
            break;
    }
}

/**
 * @brief 接收消息处理
 */
static void gwin_protocol_task_recv_msg_handle(gwin_protocol_task_msg_t *msg)
{
    uint16_t subtype = msg->subtype;
    switch(subtype)
    {
        case PROTOCOL_TASK_DATA_WAY_MCU:
            {
                gwin_protocol_parse_from_mcu(msg->data, msg->len);
            }
            break;

        default:
            break;
    }
}

/**
 * @brief 发送消息处理
 */
static void gwin_protocol_task_send_msg_handle(gwin_protocol_task_msg_t *msg)
{
    uint16_t subtype = msg->subtype;
    switch(subtype)
    {
        case PROTOCOL_TASK_DATA_WAY_MCU:
            {
                uint32_t type = msg->param;
                gwin_protocol_send_cmd_to_mcu(type);
            }
            break;

        default:
            GWIN_DEBUG("Error : subtype of send msg is unknown %d !!!", subtype);
            break;
    }
}


/**
 * @brief 任务初始化
 */
void gwin_protocol_task_init(void)
{
    #if GWIN_PROT_RX_IRQ
    gwin_protocol_task_timer_uart_rx = os_timer_create("gwin_protocol_uart_rx", 100, TRUE, NULL, gwin_protocol_uart_rx_callback);
    GWIN_OS_TIMER_ASSERT(gwin_protocol_task_timer_uart_rx);
    #endif

    gwin_protocol_task_timer_uart_tx = os_timer_create("gwin_protocol_uart_tx", 100, FALSE, NULL, gwin_protocol_uart_tx_callback);
    GWIN_OS_TIMER_ASSERT(gwin_protocol_task_timer_uart_tx);

    #if GWIN_PROT_RX_IRQ
    gwin_fifo_init(&protocol_fifo_rx_mcu.fifo, protocol_fifo_rx_mcu.buf, sizeof(protocol_fifo_rx_mcu.buf));
    gwin_fifo_init(&protocol_list_rx_mcu.fifo, (uint8_t *)protocol_list_rx_mcu.buf, sizeof(protocol_list_rx_mcu.buf));
    os_timer_start(gwin_protocol_task_timer_uart_rx, 0);
    #endif

    gwin_fifo_init(&protocol_fifo_tx_mcu.fifo, protocol_fifo_tx_mcu.buf, sizeof(protocol_fifo_tx_mcu.buf));
    gwin_fifo_init(&protocol_list_tx_mcu.fifo, (uint8_t *)protocol_list_tx_mcu.buf, sizeof(protocol_list_tx_mcu.buf));

    gwin_uart_interrupt_set_callback(gwin_protocol_recv_from_mcu);

    protocol_task_init = 1;

    gwin_protocol_task_msg_t msg = { 0 };
    msg.type = PROTOCOL_TASK_MSG_TYPE_TASK_START;
    gwin_send_msg_to_protocol_task(&msg);
}

/**
 * @brief 发送消息
 */
uint8_t gwin_send_msg_to_protocol_task(gwin_protocol_task_msg_t *p_msg)
{
    if (!protocol_task_init) return 0;

    gwin_protocol_task((void *)p_msg);
    return 1;
}


#if GWIN_PROT_RX_IRQ
/**
 * @brief 定时器 接收
 */
static void gwin_protocol_uart_rx_callback(void *arg)
{
    gwin_protocol_task_msg_t msg = { 0 };
    msg.type = PROTOCOL_TASK_MSG_TYPE_TIMER;
    msg.subtype = PROTOCOL_TASK_MSG_TIMER_SUBTYPE_UART_RX;
    gwin_send_msg_to_protocol_task(&msg);
}
#endif

/**
 * @brief 定时器 延时发送循环
 */
static void gwin_protocol_uart_tx_callback(void *arg)
{
    gwin_protocol_task_msg_t msg = { 0 };
    msg.type = PROTOCOL_TASK_MSG_TYPE_TIMER;
    msg.subtype = PROTOCOL_TASK_MSG_TIMER_SUBTYPE_UART_TX;
    gwin_send_msg_to_protocol_task(&msg);
}

/**
 * @brief 任务
 */
static void gwin_protocol_task(void *arg)
{
    gwin_protocol_task_msg_t *msg = arg;

    switch(msg->type)
    {
        case PROTOCOL_TASK_MSG_TYPE_TASK_START:
            break;

        case PROTOCOL_TASK_MSG_TYPE_TIMER:
            gwin_protocol_task_timer_msg_handle(msg);
            break;

        case PROTOCOL_TASK_MSG_TYPE_RECV:
            gwin_protocol_task_recv_msg_handle(msg);
            break;

        case PROTOCOL_TASK_MSG_TYPE_SEND:
            gwin_protocol_task_send_msg_handle(msg);
            break;
    }
}


/*-------------------------- END OF FILE ------------------------------------*/

